'use strict';

const crypto = require('crypto');
const JsEncrypt = require('node-jsencrypt');
const lodash = require('lodash');
const { Op } = require('sequelize');

module.exports = {

  /**
   * @description: 密码rsa加密
   * @param {*} data
   * @return {*}
   */
  rsaEncrypt(data) {
    const key = this.app.config.publicKey;
    const jse = new JsEncrypt();
    // 设置公钥
    jse.setPublicKey(key);
    return jse.encrypt(data);
  },


  /**
     * @description: 密码rsa解密
     * @param {*} encrypted
     * @return {*}
     */
  rsaDecrypt(encrypted) {
    const privateKey = this.app.config.privateKey;
    const jse = new JsEncrypt();
    // 私钥
    jse.setPrivateKey(privateKey);
    return jse.decrypt(encrypted);
  },

  /**
   * @description: 密码加密
   * @param {*} data
   * @param {*} key
   * @return {*}
   */
  aesEncrypt(data, key) {
    const hmac = crypto.createHash('sha256', key).update(data).digest('hex');
    return hmac;
  },


  /**
   * @description: 生成token
   * @param {*} data
   * @param {*} time
   * @return {*}
   */
  generateToken(data, time = -1) {
    const created = Math.floor(Date.now() / 1000);
    // let cert = fs.readFileSync(path.join(__dirname, '../public/rsa_private_key.pem'));//私钥
    const token = this.app.jwt.sign({
      data,
      exp: time === -1 ? time : created + time,
    }, this.app.config.jwt.secret);
    return token;
  },


  /**
   * @description: 解析token
   * @param {*} token
   * @return {*}
   */
  analysisToken(token) {
    return this.app.jwt.verify(token, this.app.jwt.secret);
  },

  /**
   * @description: 从header里获取userId
   * @param {*} ctx
   * @return {*}
   */
  getUserIdByHeader(ctx) {
    const token = ctx.request.header.authorization;
    const info = ctx.helper.analysisToken(token);
    const { data } = info;
    if (typeof data === 'string' && data.startsWith('app')) {
      return data.slice(4);
    }
    return data;
  },

  /**
   * @description: 生成随机数
   * @param {*} n
   * @return {*}
   */
  randomNum(n = 10) {
    let res = '';
    for (let i = 0; i < n; i++) {
      res += Math.floor(Math.random() * 10);
    }
    return res;
  },

  /**
   * @description: 验证码验证
   * @param {*} ctx
   * @param {*} code
   * @param {*} uuid
   * @return {*}
   */
  async verifyCaptchaCode(ctx, code, uuid) {
    const codeObj = await ctx.service.cache.get(`code_${uuid}`);
    if (!codeObj) {
      return { code: 40001, msg: '验证码过期' };
    }
    const { captchaCode, captchaUuid } = codeObj;
    ctx.logger.info('====captchaCode====', captchaCode);
    ctx.logger.info('====captchaUuid====', captchaUuid);

    if (uuid === captchaUuid && `${code}` === captchaCode) {
      return { code: 0, msg: '验证成功' };
    }
    if (`${code}` !== captchaCode) {
      return { code: 40002, msg: '验证码错误' };
    }
  },


  /**
   * @description: 数组转树
   * @param {*} list
   * @param {*} name
   * @return {*}
   */
  arrayToTree(list, name = 'children') {
    if (list.length === 1) {
      return list;
    }
    const res = [];
    const map = list.reduce((res, v) => (res[v.id] = v, res), {});
    for (const item of list) {
      if (item.parent_id === '0') {
        res.push(item);
        continue;
      }
      if (item.parent_id in map) {
        const parent = map[item.parent_id];
        parent[name] = parent[name] || [];
        parent[name].push(item);
      }
    }
    return res;


  },

  /**
   * @description: 数组对象去重
   * @param {*} arr
   * @return {*}
   */
  arrDeWeight(arr) {
    const obj = {};
    const res = [];
    arr.forEach(item => {
      if (!obj[item.id]) {
        res.push(item);
        obj[item.id] = true;
      }
    });
    return res;
  },

  /**
 * 获取两个对象数组的差集
 * @param allArr：全数组
 * @param partArr：缺省数组
 *  */

  getDifferentArr(allArr, partArr) {
    for (let i = allArr.length - 1; i >= 0; i--) {
      for (let j = 0; j < partArr.length; j++) {
        if (allArr[i].id === partArr[j].id) {
          allArr.splice(i, 1);
          break;
        }
      }
    }
    return allArr;
  },

  /**
   * @description: 根据key获取数组value
   * @param {*} arr
   * @param {*} key
   * @return {*}
   */
  getArrayProps(arr, key) {
    const keys = `${key}`;
    const res = [];
    if (arr.length > 0) {
      arr.forEach(t => {
        res.push(t[keys]);
      });
    }
    return res;
  },


  // /**
  //  * findAll请求根据rule处理query值
  //  * @param rule 规则
  //  * @param queryOrigin 原请求参数
  //  * @param ruleOther 追加规则
  //  * @param findAllParamsOther 追加搜索字段
  //  * @param keywordLikeExcludeParams 关键字keyword模糊搜索排除字段
  //  * @return {{query: {where: {}}, allRule: {offset: {default: number, type: string, required: boolean}, prop_order: {values, type: string, required: boolean}, limit: {type: string, required: boolean}, order: {values: [string, string, string], type: string, required: boolean}}}}
  //  */
  findAllParamsDeal(ctx, options) {
    const { rule, queryOrigin, ruleOther = {}, findAllParamsOther = {}, keywordLikeExcludeParams = [] } = options;
    const _rule = lodash.cloneDeep(rule);
    const query = {
      where: {},
    };
    for (const ruleKey in _rule) {
      _rule[ruleKey].required = false;
    }
    const findAllParams = {
      keyword: {
        type: 'string',
        trim: true,
        required: false,
        max: 36,
      },
      prop_order: {
        type: 'enum',
        required: false,
        values: [ ...Object.keys(_rule), '' ],
      },
      order: {
        type: 'enum',
        required: false,
        values: [ 'desc', 'asc', '' ],
      },
      pageSize: {
        type: 'number',
        required: false,
      },
      current: {
        type: 'number',
        required: false,
        default: 1,
      },
      ...findAllParamsOther,
    };
    const allRule = {
      ..._rule,
      ...ruleOther,
      ...findAllParams,
    };
      // 根据rule处理query，剔除非rule检查字段
    for (const queryKey in queryOrigin) {
      if (_rule.hasOwnProperty(queryKey)) {
        // 字段like = true模糊查询
        if (_rule[queryKey].like) {
          query.where[queryKey] = { [Op.like]: `%${queryOrigin[queryKey]}%` };
        } else {
          query.where[queryKey] = queryOrigin[queryKey];
        }
      }
      if (allRule.hasOwnProperty(queryKey)) {
        query[queryKey] = queryOrigin[queryKey];
      }
    }
    // 如果搜索参数queryOrigin中带有keyword，且不为空字符串，则视keyword为模糊搜索
    if (queryOrigin.hasOwnProperty('keyword') && queryOrigin.keyword.trim() !== '') {
      query.where[Op.or] = [];
      for (const queryKey in _rule) {
        // 非模糊搜索排除字段的所有rule中的字段, 且数据类型为string，做模糊查询
        if (!keywordLikeExcludeParams.includes(queryKey) && _rule[queryKey].type === 'string') {
          query.where[Op.or].push({ [queryKey]: { [Op.like]: `%${queryOrigin.keyword.trim()}%` } });
        }
      }
    }
    return {
      allRule,
      query,
    };
  },
};


module.exports.body = {
  SUCCESS({ ctx, data, msg }) {
    ctx.body = {
      code: 0,
      data,
      msg,
    };
    ctx.status = 200;
  },

  LOGIN_SUCCESS({ ctx, data, msg, token }) {
    ctx.body = {
      code: 0,
      data,
      msg,
      token,
    };
    ctx.status = 200;
  },


  // [POST/PUT/PATCH]：用户新建或修改数据成功。
  CREATED_UPDATE({ ctx, res = null, msg = '新建或修改数据成功' }) {
    ctx.body = {
      code: 0,
      data: res,
      msg,
    };
    ctx.status = 200;
  },

  /*
     * @description [DELETE]：用户删除数据成功。
     */
  NO_CONTENT({ ctx, res = null, msg = '删除数据成功' }) {
    ctx.body = {
      code: 0,
      data: res,
      msg,
    };
    ctx.status = 200;
  },

  // [POST/PUT/PATCH]：用户发出的请求有错误，服务器没有进行新建或修改数据的操作
  INVALID_REQUEST({ ctx, res = null, msg = '请求有错误，服务器没有进行新建、修改、删除数据的操作', code = 400, status = 200 }) {
    ctx.body = {
      code,
      data: res,
      msg,
    };
    ctx.status = status;
  },

  // [*]：表示用户没有认证（令牌、用户名、密码错误）。
  UNAUTHORIZED({ ctx, res = null, msg = '没有认证（令牌、用户名、密码错误）', status = 200 }) {
    ctx.body = {
      code: 401,
      data: res,
      msg,
    };
    ctx.status = status;
  },

  // [*] 表示用户得到授权（与401错误相对），但是访问是被禁止的。
  FORBIDDEN({ ctx, res = null, msg = '权限不足，访问被禁止' }) {
    ctx.body = {
      code: 403,
      data: res,
      msg,
    };
    ctx.status = 200;
  },

  // [*]：用户发出的请求针对的是不存在的记录，服务器没有进行操作
  NOT_FOUND({ ctx, res = null, msg = '资源未找到', status = 200 }) {
    ctx.body = {
      code: 404,
      data: res,
      msg,
    };
    ctx.status = status;
  },

  // [*] 参数发生验证错误。
  VALIDATION_FAILED({ ctx, res = null, msg = '参数发生验证错误' }) {
    ctx.body = {
      code: 422,
      data: res,
      msg,
    };
    ctx.status = 200;
  },

  // 异常错误
  ERROR({ ctx, msg = '系统异常' }) {
    ctx.body = {
      code: 204,
      data: null,
      msg,
    };
    ctx.status = 200;
  },
};
